package com.hqd.ch03.v50.web.context.support;

import com.hqd.ch03.v50.beans.factory.DisposableBean;
import com.hqd.ch03.v50.config.Scope;
import com.hqd.ch03.v50.factory.ObjectFactory;

import javax.servlet.ServletContext;
import java.util.LinkedHashMap;
import java.util.Map;

public class ServletContextScope implements Scope, DisposableBean {

    private final ServletContext servletContext;

    private final Map<String, Runnable> destructionCallbacks = new LinkedHashMap<>();


    /**
     * Create a new Scope wrapper for the given ServletContext.
     *
     * @param servletContext the ServletContext to wrap
     */
    public ServletContextScope(ServletContext servletContext) {
        this.servletContext = servletContext;
    }


    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Object scopedObject = this.servletContext.getAttribute(name);
        if (scopedObject == null) {
            scopedObject = objectFactory.getObject();
            this.servletContext.setAttribute(name, scopedObject);
        }
        return scopedObject;
    }

    @Override

    public Object remove(String name) {
        Object scopedObject = this.servletContext.getAttribute(name);
        if (scopedObject != null) {
            synchronized (this.destructionCallbacks) {
                this.destructionCallbacks.remove(name);
            }
            this.servletContext.removeAttribute(name);
            return scopedObject;
        } else {
            return null;
        }
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        synchronized (this.destructionCallbacks) {
            this.destructionCallbacks.put(name, callback);
        }
    }

    @Override

    public Object resolveContextualObject(String key) {
        return null;
    }

    @Override

    public String getConversationId() {
        return null;
    }


    /**
     * Invoke all registered destruction callbacks.
     * To be called on ServletContext shutdown.
     *
     * @see org.springframework.web.context.ContextCleanupListener
     */
    @Override
    public void destroy() {
        synchronized (this.destructionCallbacks) {
            for (Runnable runnable : this.destructionCallbacks.values()) {
                runnable.run();
            }
            this.destructionCallbacks.clear();
        }
    }

}
